home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gigarom 1
/
Gigarom Macintosh Archives (Quantum Leap)(CDRM1080320)(1993).iso
/
FILES
/
DEV
/
I-Z
/
TransSkel.cpt
/
transSkelpas
< prev
Wrap
Text File
|
1987-03-06
|
36KB
|
1,351 lines
{ TransSkel version 1.02 - Transportable application skeleton}
{ TransSkel is public domain and was originally written in LightSpeed C by:}
{ Paul DuBois}
{ Wisconsin Regional Primate Research Center}
{ 1220 Capital Court}
{ Madison WI 53706 USA}
{ UUCP: allegra,ihnp4,seismo!uwvax!uwmacc!dubois}
{ ARPA: dubois@unix.macc.wisc.edu}
{ dubois@rhesus.primate.wisc.edu}
{ The Pascal Version of TransSkel is public domain and was ported by }
{ Owen Hartnett }
{ Ωhm Software }
{ 163 Richard Drive }
{ Tiverton, RI 02878 }
{ CSNET: omh@cs.brown.edu.CSNET }
{ ARPA: omh%cs.brown.edu@relay.cs.net-relay.ARPA }
{ UUCP: [ihnp4,allegra]!brunix !omh }
{ Psychic Wavelength: 182.2245 Meters (sorry, couldn't resist) }
{ This version of TransSkel written for Lightspeed Pascal. Lightspeed Pascal is a}
{ trademark of:}
{ THINK Technologies, Inc}
{ 420 Bedford Street Suite 350}
{ Lexington, MA 02173 USA}
{ History}
{ 06/13/86 Beta version.}
{ 08/27/86 Version number changed to 1.01.}
{ v1.0 DoGrow bug fixed - the port at the point of the}
{ InvalRect could have been anything; the fix is to set}
{ the port to the grown window first. This also explains}
{ why the kludge to DoActivate in v1.0 worked.}
{ 10/02/86 Version number changed to 1.02, as a result of adding}
{ modifications by David W. Berry (well!dwb@lll-lcc.arpa)}
{ for supporting window zooming. Also used his modifications}
{ for supporting modeless dialogs (though not in the same}
{ form). Dialogs can be #define'd on or off.}
{ 12/24/86 Finished final debugging of Pascal version. (well, final as they }
{ come.) Dialogs cannot be defined off. Santa Claus assists with final }
{ modification.}
UNIT TransSkelpas;
INTERFACE
PROCEDURE SkelInit;
PROCEDURE SkelMain;
PROCEDURE SkelWhoa;
PROCEDURE SkelClobber;
PROCEDURE SkelMenu (theMenu : MenuHandle;
pSelect : ProcPtr;
pClobber : ProcPtr);
PROCEDURE SkelRmveMenu (theMenu : MenuHandle);
PROCEDURE SkelApple (aboutTitle : Str255;
aboutProc : ProcPtr);
PROCEDURE SkelWindow (theWind : WindowPtr;
pMouse, pKey, pUpdate, pActivate, pClose, pClobber, pIdle : ProcPtr;
frontOnly : Boolean);
PROCEDURE SkelRmveWind (theWind : WindowPtr);
PROCEDURE SkelDialog (theDialog : DialogPtr;
pEvent, pClose, pClobber : ProcPtr);
PROCEDURE SkelRmveDlog (theDialog : DialogPtr);
PROCEDURE SkelGrowBounds (theWind : WindowPtr;
hLO, vLo, hHi, vHi : integer);
PROCEDURE SkelEventMask (mask : integer);
PROCEDURE SkelGetEventMask (mask : integer);
PROCEDURE SkelBackground (p : ProcPtr);
PROCEDURE SkelGetBackground (VAR p : ProcPtr);
PROCEDURE SkelEventHook (p : ProcPtr);
PROCEDURE SkelGetEventHook (VAR p : ProcPtr);
PROCEDURE SkelDlogMask (mask : integer);
PROCEDURE SkelGetDlogMask (VAR mask : integer);
IMPLEMENTATION
CONST
mBarHeight = 20; { menu bar height. All window sizing}
{ This window zooming stuff may need to be removed if you use the new Rom libraries }
{ if not, then you can add zooming without the overhead of the new Rom libs. See TrackBox }
{ routine also. }
inZoomIn = 7;
inZoomOut = 8;
{ Window and Menu handler types, constants, variables.}
{ whList and mhList are the lists of window and menu handlers.}
{ whClobOnRmve and mhClobOnRmve are true if the handler disposal proc}
{ is to be called when a handler is removed. They are temporarily set}
{ false when handlers are installed for windows or menus that already}
{ have handlers - the old handler is removed WITHOUT calling the}
{ disposal proc.}
{ Default lower limits on window sizing of 80 pixels both directions is}
{ sufficient to allow text windows room to draw a grow box and scroll}
{ bars without having the thumb and arrows overlap. These values may}
{ be changed if such a constraint is undesirable with SkelGrowBounds.}
{ Default upper limits are for the Macintosh, not the Lisa, but are set}
{ per machine in SkelInit.}
TYPE
WHandlerPtr = ^WHandler;
WHandlerHnd = ^WHandlerPtr;
WHandler = RECORD
whWind : WindowPtr; {window/dialog to be handled }
whClobber : ProcPtr; { data structure disposal proc }
whMouse : ProcPtr; { mouse-click handler proc }
whKey : ProcPtr; { key-click handler proc }
whUpdate : ProcPtr; { update handler proc }
whActivate : ProcPtr; { activate event handler proc }
whClose : ProcPtr; { close "event" handler proc }
whIdle : ProcPtr; { main loop proc }
whEvent : ProcPtr; { dialog event proc }
whGrow : Rect; { limits on window sizing }
whSized : Boolean; { true = window was resized }
whFrontOnly : Boolean; { true = idle only when active }
whNext : WHandlerHnd; { next window handler }
END;
MHandlerPtr = ^MHandler;
MHandlerHnd = ^MHandlerPtr;
MHandler = RECORD
mhID : integer; { menu id }
mhSelect : ProcPtr; { item selection handler proc }
mhClobber : ProcPtr; { menu disposal handler proc }
mhNext : MHandlerHnd; { next menu handler }
END;
EventPtr = ^EventRecord;
VAR
whList : WHandlerHnd; { list of menu handlers }
whClobOnRmve : Boolean;
growRect : Rect;
mhList : MHandlerHnd;
mhClobOnRmve : Boolean;
{ Variables for default Apple menu handler. appleID is set to 1 if}
{ SkelApple is called and is the id of the Apple menu, appleAboutProc}
{ is the procedure to execute if there is an About... item and it's}
{ chosen from the Apple menu. If doAbout is true, then the menu}
{ contains the About... item, otherwise it's just desk accessories.}
appleMenu : MenuHandle;
appleID : integer;
appleAboutProc : ProcPtr;
doAbout : Boolean;
{ Miscellaneous}
{ screenPort points to the window manager port.}
{ doneFlag determines when SkelMain returns. It is set by calling}
{ SkelWhoa(), which the host does to request a halt.}
{ pBkgnd points to a background procedure, to be run during event}
{ processing. Set it with SkelBackground. If nil, there's no}
{ procedure.}
{ pEvent points to an event-inspecting hook, to be run whenever an}
{ event occurs. Set it with SkelEventHook. If nil, there's no}
{ procedure.}
{ eventMask controls the event types requested in the GetNextEvent}
{ call in SkelMain.}
{ diskInitPt is the location at which the disk initialization dialog}
{ appears, if an uninitialized disk is inserted.}
screenPort : GrafPtr;
doneFlag : integer;
pBkgnd : ProcPtr;
pEvent : ProcPtr;
eventMask : integer;
diskInitPt : Point;
{ Events that are passed to dialogs. Others are ignored.}
{ Standard mask passes , mousedown, keydown, autokey, update,}
{ activate and null events. Null events are controlled by bit 0.}
dlogEventMask : integer;
pEventflag : Boolean;
{ Rather than including the entire new ROM libraries, with all the other stuff you might not use }
{ I've instead included just the Zoom box stuff here. Depending on your status, you can either }
{ leave things as they are, and only use zooming from the new Rom libs, or comment out the }
{ calls, and include the new Rom libraries if you want to incorporate other new Rom calls }
FUNCTION TrackBox (theWindow : WindowPtr;
thePt : Point;
partCode : INTEGER) : BOOLEAN;
INLINE
$A83B;
{ -------------------------------------------------------------------- }
{ Internal (private) Routines }
{ -------------------------------------------------------------------- }
{ Get handler associated with user or dialog window.}
{ Return nil if window doesn't belong to any known handler.}
{ This routine is absolutely fundamental to TransSkel.}
FUNCTION GetWDHandler (theWind : WindowPtr) : WHandlerHnd;
VAR
h : WHandlerHnd;
BEGIN
h := WhList;
GetWDHandler := NIL;
WHILE h <> NIL DO
IF h^^.whWind = theWind THEN
BEGIN
GetWDHandler := h;
h := NIL;
END
ELSE
h := WHandlerHnd(h^^.whNext);
END;
FUNCTION GetWHandler (theWind : WindowPtr) : WHandlerHnd;
VAR
h : WHandlerHnd;
myPeek : WindowPeek;
BEGIN
h := GetWDHandler(theWind);
myPeek := WindowPeek(theWind);
IF h <> NIL THEN
BEGIN
IF mypeek^.windowKind <> dialogKind THEN
GetWHandler := h;
END
ELSE
GetWHandler := NIL;
END;
{ Get handler associated with dialog window.}
{ Return nil if window doesn't belong to any known handler.}
{ The order of the two tests is critical: theDialog might be nil.}
FUNCTION GetDHandler (theDialog : WindowPtr) : WHandlerHnd;
VAR
h : WHandlerHnd;
myPeek : WindowPeek;
BEGIN
h := GetWDHandler(theDialog);
myPeek := WindowPeek(theDialog);
IF h <> NIL THEN
BEGIN
IF mypeek^.windowKind = dialogKind THEN
GetDHandler := h;
END
ELSE
GetDHandler := NIL;
END;
{The following procedures are Pascal "glue" that allows Pascal to call a Procedure }
{ from a ProcPtr. It is similar to (*p) () construct used in the C dialect. Different }
{ procedures are necessary for the reason of Pascal's strongly typed parameter }
{ list. Fortunately, there are not too many calls which use different param lists }
PROCEDURE callpMouse (thePoint : Point;
theTime : longint;
theMods : integer;
myProc : ProcPtr);
INLINE
$205f, {movea.l (a7)+,a0 ; (a0) is a ptr to string, 4(a0) is mode}
$4e90;
PROCEDURE callpKey (theChar : char;
theMods : integer;
myProc : ProcPtr);
INLINE
$205f, {movea.l (a7)+,a0 ; (a0) is a ptr to string, 4(a0) is mode}
$4e90;
PROCEDURE callpEvent (theitem : integer;
theEvent : EventPtr;
myProc : ProcPtr);
INLINE
$205f, {movea.l (a7)+,a0 ; (a0) is a ptr to string, 4(a0) is mode}
$4e90;
FUNCTION callotherEvent (theEvent : EventPtr;
myProc : ProcPtr) : Boolean;
INLINE
$205f, $4e90;
PROCEDURE callpBoolean (myBool : Boolean;
myProc : ProcPtr);
{ Two calls use Booleans as one parameter arguments. This procedure handles }
{ both of them. }
INLINE
$205f, {movea.l (a7)+,a0 ; (a0) is a ptr to string, 4(a0) is mode}
$4e90;
PROCEDURE callpInt (myInt : integer;
myProc : ProcPtr);
{ Two calls use Booleans as one parameter arguments. This procedure handles }
{ both of them. }
INLINE
$205f, {movea.l (a7)+,a0 ; (a0) is a ptr to string, 4(a0) is mode}
$4e90;
PROCEDURE callpMenu (myMenu : MenuHandle;
myProc : ProcPtr);
{ Handle removeal of menus. }
INLINE
$205f, {movea.l (a7)+,a0 ; (a0) is a ptr to string, 4(a0) is mode}
$4e90;
PROCEDURE callpnoarg (myProc : ProcPtr);
{ For all the Procedures that are called with no arguments }
INLINE
$205f, {movea.l (a7)+,a0 ; (a0) is a ptr to string, 4(a0) is mode}
$4e90;
{ General menu-handler. Just passes selection to the handler's}
{ select routine. If the select routine is nil, selecting items from}
{ the menu is a nop.}
PROCEDURE DoMenuCommand (command : longint);
VAR
menu : integer;
item : integer;
mh : MHandlerHnd;
p : ProcPtr;
BEGIN
menu := HiWord(command);
item := LoWord(command);
mh := mhList;
WHILE (mh <> NIL) DO
BEGIN
p := mh^^.mhSelect;
IF ((menu = mh^^.mhID) AND (p <> NIL)) THEN
BEGIN
callpInt(item, p);
mh := NIL;
END
ELSE
mh := mh^^.mhNext;
END;
HiliteMenu(0);
END;
{ Apple menu handler}
{ DoAppleItem: If the first item was chosen, and there's an "About..."}
{ item, call the procedure associated with it (if not nil). If there}
{ is no "About..." item or the item was not the first one, then open}
{ the associated desk accessory. The port is saved and restored}
{ because OpenDeskAcc does not always preserve it correctly.}
{ DoAppleClobber disposes of the Apple menu.}
PROCEDURE DoAppleItem (item : integer);
VAR
curPort : GrafPtr;
str : Str255;
ignore : integer;
BEGIN
IF doAbout AND (item = 1) THEN
BEGIN
IF appleAboutProc <> NIL THEN
callpnoarg(appleAboutProc);
END
ELSE
BEGIN
GetPort(curPort);
GetItem(appleMenu, item, str);
ignore := OpenDeskAcc(str);
SetPort(curPort);
END;
END;
PROCEDURE DoAppleClobber;
BEGIN
DisposeMenu(appleMenu);
END;
{ -------------------------------------------------------------------- }
{ Window-handler routing routines }
{ }
{ Each routine sets the port to the handler's window before executing }
{ the handler procedure. }
{ -------------------------------------------------------------------- }
{ Pass local mouse coordinates, click time, and the modifiers flag}
{ word to the handler.}
PROCEDURE DoMouse (h : WHandlerHnd;
theEvent : EventPtr);
VAR
p : ProcPtr;
thePt : Point;
BEGIN
IF (h <> NIL) THEN
BEGIN
SetPort(h^^.whWind);
p := h^^.whMouse;
IF p <> NIL THEN
BEGIN
thePt := theEvent^.where;
GlobalToLocal(thePt);
callpMouse(thePt, theEvent^.when, theEvent^.modifiers, p);
END;
END;
END;
{ Pass the character and the modifiers flag word to the handler.}
PROCEDURE DoKey (h : WHandlerHnd;
ch : char;
mods : integer);
VAR
p : ProcPtr;
BEGIN
IF h <> NIL THEN
BEGIN
SetPort(h^^.whWind);
p := h^^.whKey;
IF p <> NIL THEN
callpKey(ch, mods, p);
END;
END;
PROCEDURE DoUpdate (h : WHandlerHnd);
VAR
rh : WhandlerHnd;
p : ProcPtr;
updPort, tmpPort : GrafPtr;
BEGIN
rh := h;
IF rh <> NIL THEN
BEGIN
GetPort(tmpPort);
updPort := rh^^.whWind;
SetPort(updPort);
BeginUpdate(updPort);
p := rh^^.whUpdate;
IF p <> NIL THEN
BEGIN
callpBoolean(rh^^.whSized, p);
rh^^.whSized := false;
END;
EndUpdate(updPort);
SetPort(tmpPort);
END;
END;
PROCEDURE DoActivate (h : WHandlerHnd;
active : Boolean);
VAR
p : ProcPtr;
BEGIN
IF h <> NIL THEN
p := h^^.whActivate
ELSE
p := NIL;
IF (h <> NIL) AND (p <> NIL) THEN
BEGIN
SetPort(h^^.whWind);
callpBoolean(active, p);
END;
END;
{ Execute a window handler's close proc. This may be used by handlers}
{ for temp windows that want to remove themselves when the window}
{ is closed: they can call SkelRmveWind to dispose of the window}
{ and remove the handler from the window handler list. Thus, windows}
{ may be dynamically created and destroyed without filling up the}
{ handler list with a bunch of invalid handlers.}
{ If the handler doesn't have a close proc, just hide the window.}
{ The host should provide some way of reopening the window (perhaps}
{ a menu selection). Otherwise the window will be lost from user}
{ control if it is hidden, since it won't receive user events.}
{ The port is set to the window manager port after calling the}
{ handler proc, to avoid a dangling port.}
{ This is called both for regular and dialog windows.}
PROCEDURE DoClose (h : WHandlerHnd);
VAR
rh : WHandlerHnd;
p : ProcPtr;
BEGIN
rh := h;
IF rh <> NIL THEN
BEGIN
SetPort(rh^^.whWind);
p := rh^^.whClose;
IF (p <> NIL) THEN
callpnoarg(p)
ELSE
HideWindow(rh^^.whWind);
SetPort(screenPort);
END;
END;
PROCEDURE DoClobber (h : WHandlerHnd);
VAR
p : ProcPtr;
BEGIN
IF (h <> NIL) THEN
BEGIN
SetPort(h^^.whWind);
p := h^^.whClobber;
IF p <> NIL THEN
callpnoarg(p);
SetPort(screenPort);
END;
END;
PROCEDURE DoIdle (h : WHandlerHnd);
VAR
p : ProcPtr;
tmpPort : GrafPtr;
BEGIN
IF (h <> NIL) THEN
BEGIN
GetPort(tmpPort);
SetPort(h^^.whWind);
p := h^^.whIdle;
IF (p <> NIL) THEN
callpnoarg(p);
SetPort(tmpPort);
END;
END;
{ Handle event if it's for a dialog. The event must be one of}
{ those that is passed to dialogs according to dlogEventMask.}
{ This mask can be set so that disk-inserts, for instance, don't}
{ get eaten up.}
FUNCTION DoDialog (theEvent : EventPtr) : Boolean;
VAR
dh : WHandlerHnd;
theDialog : DialogPtr;
what : integer;
item : integer;
tmpPort : GrafPtr;
ignore : Boolean;
testme : longint;
BEGIN
{ handle command keys before they get to IsDialogEvent}
what := theEvent^.what;
testme := BitShift(longint(1), what);
testme := BitAnd(testme, longint(dlogEventMask));
IF (((what = keydown) OR (what = autokey)) AND Boolean(BitAnd(theEvent^.modifiers, cmdkey))) THEN
BEGIN
DoMenuCommand(MenuKey(Char(BitAnd(theEvent^.message, charCodeMask))));
DoDialog := true;
END
ELSE IF testme > 0 THEN
IF IsDialogEvent(theEvent^) THEN
BEGIN
IF DialogSelect(theEvent^, theDialog, item) THEN
BEGIN
dh := WHandlerHnd(GetDHandler(theDialog));
IF (dh <> NIL) THEN
IF (dh^^.whEvent <> NIL) THEN
BEGIN
GetPort(tmpPort);
SetPort(theDialog);
callpEvent(item, theEvent, dh^^.whEvent);
SetPort(tmpPort);
END;
END;
DoDialog := true;
END
ELSE
DoDialog := false;
END;
{ -------------------------------------------------------------------- }
{ Event-handling routines }
{ -------------------------------------------------------------------- }
{ Have either sized or zoomed the window. Invalidate it to force}
{ an update and set the 'resized' flag in the window handler true.}
PROCEDURE TriggerUpdate (h : WHandlerHnd;
thePort : GrafPtr);
BEGIN
SetPort(thePort);
InvalRect(thePort^.portRect);
IF (h <> NIL) THEN
BEGIN
h^^.whSized := true;
END;
END;
{ Size a window. If the window has a handler, use the grow limits}
{ in the handler record, otherwise use the defaults.}
{ The portRect is invalidated to force an update event. (The port}
{ must be set first, as it could be pointing anywhere.) The handler's}
{ update procedure should check the parameter passed to it to check}
{ whether the window has changed size, if it needs to adjust itself to}
{ the new size. THIS IS A CONVENTION. Update procs must notice grow}
{ "events", there is no procedure specifically for such events.}
{ The clipping rectangle is not reset. If the host application}
{ keeps the clipping set equal to the portRect or something similar,}
{ then it will have to arrange to treat window growing with more}
{ care.}
PROCEDURE DoGrow (h : WHandlerHnd;
thePort : GrafPtr;
StartPt : Point);
VAR
r : Rect;
growRes : longint;
BEGIN
IF (h <> NIL) THEN
BEGIN
r := h^^.whGrow;
END
ELSE
r := growRect;
growRes := GrowWindow(thePort, startPt, r);
IF growRes <> 0 THEN
BEGIN
SizeWindow(thePort, LoWord(growRes), HiWord(growRes), false);
TriggerUpdate(h, thePort);
END;
END;
{ Remove following procedure if using new rom library }
PROCEDURE ZoomWindow (theWindow : GrafPtr;
partCode : INTEGER;
front : BOOLEAN);
INLINE
$A83A;
{ Zoom the current window. Very similar to DoGrow}
PROCEDURE DoZoom (h : WHandlerHnd;
thePort : GrafPtr;
partcode : integer);
BEGIN
ZoomWindow(thePort, partcode, false);
TriggerUpdate(h, thePort);
END;
{ General event handler}
PROCEDURE DoEvent (theEvt : EventPtr);
VAR
theEvent : EventPtr;
evtPt : Point;
evtPort : GrafPtr;
evtPart : integer;
evtChar : char;
evtMods : integer;
h : WHandlerHnd;
r : Rect;
ignore : integer;
BEGIN
theEvent := theEvt;
IF (DoDialog(theEvent)) THEN
BEGIN
END
ELSE
BEGIN
evtPt := theEvent^.where;
CASE theEvent^.what OF
nullEvent :
;
{ Mouse click. Get the window that the click occurred in, and the}
{ part of the window.}
mouseDown :
BEGIN
evtPart := FindWindow(evtPt, evtPort);
h := GetWHandler(evtPort);
CASE evtPart OF
{ Click in a desk accessory window. Pass back to the system.}
inSysWindow :
SystemClick(theEvent^, evtPort);
{ Click in menu bar. Track the mouse and execute selected command,}
{ if any.}
inMenuBar :
DoMenuCommand(MenuSelect(evtPt));
{ Click in grow box. Resize window.}
inGrow :
DoGrow(h, evtPort, evtPt);
{ Click in title bar. Drag the window around. Leave at least}
{ 4 pixels visible in both directions.}
inDrag :
BEGIN
r := screenPort^.portRect;
r.top := r.top + mBarHeight; { Skip down past menu bar }
InsetRect(r, 4, 4);
DragWindow(evtPort, evtPt, r);
END;
{ Click in close box. Call the close proc if the window has one.}
inGoAway :
IF (TrackGoAway(evtPort, evtPt)) THEN
DoClose(GetWDHandler(evtPort));
{ Click in content region. If the window wasn't frontmost (active),}
{ just select it, otherwise pass the click to the window's mouse}
{ click handler.}
inContent :
IF (evtPort <> FrontWindow) THEN
SelectWindow(evtPort)
ELSE
DoMouse(h, theEvent);
{ Click in zoom box. Track the click and then zoom the window if}
{ necessary}
inZoomin, inZoomOut :
IF (TrackBox(evtPort, evtPt, evtPart)) THEN
DoZoom(h, evtport, evtPart);
OTHERWISE
;
END;{mousedown}
END;
{ Key event. If the command key was down, process as menu item}
{ selection, otherwise pass the character and the modifiers flags}
{ to the active window's key handler.}
{ If dialogs are supported, there's no check for command-key}
{ equivalents, since that would have been checked in DoDialog.}
keydown, autokey :
BEGIN
evtChar := char(BitAnd(theEvent^.message, charCodeMask));
evtMods := theEvent^.modifiers;
IF BitAnd(evtMods, cmdKey) > 0 THEN
DoMenuCommand(menuKey(evtChar))
ELSE
DoKey(GetWHandler(FrontWindow), evtChar, evtMods);
END;
{ Update a window.}
updateEvt :
DoUpdate(GetWHandler(WindowPtr(theEvent^.message)));
{ Activate or deactivate a window.}
activateEvt :
DoActivate(GetWHandler(WindowPtr(theEvent^.message)), (BitAnd(theEvent^.modifiers, activeFlag) <> 0));
{ handle inserts of uninitialized disks}
diskEvt :
IF (HiWord(theEvent^.message) <> noErr) THEN
BEGIN
DILoad;
ignore := DIBadMount(diskInitPt, theEvent^.message);
DIUnload;
END;
OTHERWISE
END;
END;
END;
{ -------------------------------------------------------------------- }
{ Interface (public) Routines }
{ -------------------------------------------------------------------- }
{ Initialize the various Macintosh Managers.}
{ Set default upper limits on window sizing.}
{ FlushEvents does NOT toss disk insert events, so that disks}
{ inserted while the application is starting up don't result}
{ in dead drives.}
PROCEDURE SkelInit;
BEGIN
InitCursor;
whList := NIL;
whClobOnRmve := true;
SetRect(growRect, 80, 80, 512, 342 - mBarHeight);
mhList := NIL;
mhClobOnRmve := true;
appleID := 0;
appleAboutProc := NIL;
doAbout := false;
doneflag := 0;
pBkgnd := NIL;
pEvent := NIL;
pEventflag := false;
eventmask := everyEvent;
diskInitPt.v := 120;
diskInitPt.h := 100;
dlogEventMask := $16b;
{ Set upper limits of window sizing to machine screen size. Allow}
{ for the menu bar.}
GetWMgrPort(screenport);
growRect.right := screenPort^.portRect.right;
growRect.bottom := screenPort^.portRect.bottom - mBarHeight;
END;
{ Main loop.}
{ Task care of DA's with SystemTask.}
{ Run background task if there is one.}
{ If there is an event, check for an event hook. If there isn't}
{ one defined, or if there is but it returns false, call the}
{ general event handler. (Hook returns true if TransSkel should}
{ ignore the event.)}
{ If no event, call the "no-event" handler for the front window and for}
{ any other windows with idle procedures that are always supposed}
{ to run. This is done in such a way that it is safe for idle procs}
{ to remove the handler for their own window if they want (unlikely,}
{ but...) This loop doesn't check whether the window is really}
{ a dialog window or not, but it doesn't have to, because such}
{ things always have a nil idle proc.}
{ }
{ doneFlag is reset upon exit. This allows it to be called}
{ repeatedly, or recursively.}
{ If dialogs are supported, null events are looked at (in SkelMain)}
{ and passed to the event handler. This is necessary to make sure}
{ DialogSelect gets called repeatedly, or the caret won't blink if}
{ a dialog has any editText items.}
{ If an event-inspecting hook is installed, null events are not passed}
{ to it.}
PROCEDURE SkelMain;
VAR
theEvent : EventRecord;
wh, wh2 : WHandlerHnd;
w : WindowPtr;
haveEvent, testpevent, testbool : Boolean;
BEGIN
WHILE (doneFlag = 0) DO
BEGIN
SystemTask;
IF (pBkgnd <> NIL) THEN
callpnoarg(pBkgnd);
haveEvent := GetNextEvent(eventMask, theEvent);
IF (pEvent <> NIL) THEN
testpevent := CallotherEvent(@theEvent, pEvent)
ELSE
testpevent := false;
testbool := haveEvent AND (testpevent = false);
IF ((pEvent = NIL) OR testbool) THEN
DoEvent(@theEvent);
IF NOT haveEvent THEN
BEGIN
wh := whList;
WHILE (wh <> NIL) DO
BEGIN
wh2 := wh^^.whNext;
w := wh^^.whWind;
IF ((w = FrontWindow) OR NOT wh^^.whFrontOnly) THEN
BEGIN
SystemTask;
DoIdle(wh);
END;
wh := wh2;
END;
END;
END;
doneFlag := 0;
END;
{ Tell SkelMain to stop}
PROCEDURE SkelWhoa;
BEGIN
doneFlag := 1;
END;
{ Clobber all the menu, window and dialog handlers}
PROCEDURE SkelClobber;
BEGIN
WHILE (whList <> NIL) DO
BEGIN
SkelRmveWind(whList^^.whWind);
END;
WHILE (mhList <> NIL) DO
BEGIN
SkelRmveMenu(GetMHandle(mhList^^.mhID));
END;
END;
{ -------------------------------------------------------------------- }
{ Menu-handler interface routines }
{ -------------------------------------------------------------------- }
{ Install handler for a menu. Remove any previous handler for it.}
{ Pass the following parameters:}
{ theMenu Handle to the menu to be handled. Must be created by host.}
{ pSelect Proc that handles selection of items from menu. If this is}
{ nil, the menu is installed, but nothing happens when items}
{ are selected from it.}
{ pClobber Proc for disposal of handler's data structures. Usually}
{ nil for menus that remain in menu bar until program}
{ termination.}
{ The menu is installed and drawn in the menu bar.}
PROCEDURE SkelMenu;
VAR
mh : MHandlerHnd;
myHand : Handle;
BEGIN
mhClobOnRmve := false;
SkelRmveMenu(theMenu);
mhClobOnRmve := true;
myHand := NewHandle(Sizeof(MHandler));
mh := MHandlerHnd(myHand);
mh^^.mhNext := mhList;
mhList := MHandlerHnd(myHand);
mh^^.mhID := theMenu^^.menuID; { get menu id number }
mh^^.mhSelect := pSelect; { install selection handler }
mh^^.mhClobber := pClobber; { install disposal handler }
InsertMenu(theMenu, 0); { put menu at end of menu bar }
DrawMenuBar;
END;
{ Remove a menu handler. This calls the handler's disposal routine}
{ and then takes the handler out of the handler list and disposes}
{ of it.}
{ Note that the menu MUST be deleted from the menu bar before calling}
{ the clobber proc, because the menu bar will end up filled with}
{ garbage if the menu was allocated with NewMenu (see discussion of}
{ DisposeMenu in Menu Manager section of Inside Macintosh).}
PROCEDURE SkelRmveMenu;
VAR
mID : integer;
h, h2 : MHandlerHnd;
p : ProcPtr;
returnflag : Boolean;
BEGIN
mID := theMenu^^.menuID;
returnflag := false;
IF mhlist <> NIL THEN
BEGIN
IF mhList^^.mhID = mID THEN
BEGIN
h2 := mhlist;
mhList := h2^^.mhNext;
END
ELSE
BEGIN
h := mhList;
WHILE (h <> NIL) AND NOT returnflag DO
BEGIN
h2 := h^^.mhNext;
IF (h2 = NIL) THEN
BEGIN
h := NIL;
returnflag := true;
END
ELSE IF h2^^.mhID = mID THEN
BEGIN
h^^.mhNext := h2^^.mhNext;
h := NIL;
END;
IF h <> NIL THEN
h := h2;
END;
END;
IF NOT returnflag THEN
BEGIN
DeleteMenu(mID);
DrawMenuBar;
p := h2^^.mhClobber;
IF mhClobOnRmve AND (p <> NIL) THEN
callpMenu(theMenu, p);
DisposHandle(Handle(h2));
END;
END;
END;
{ Install a handler for the Apple menu.}
{ SkelApple is called if TransSkel is supposed to handle the apple}
{ menu itself. The title is the title of the first item. If nil,}
{ then only desk accessories are put into the menu. If not nil, then}
{ the title is entered as the first item, followed by a gray line,}
{ then the desk accessories.}
PROCEDURE SkelApple;
VAR
appleTitle : Str255;
BEGIN
appleTitle := ' ';
appleTitle[1] := char($14);
appleID := 1;
AppleMenu := NewMenu(appleID, appleTitle);
IF aboutTitle <> '' THEN
BEGIN
doAbout := true;
AppendMenu(appleMenu, aboutTitle);
AppendMenu(appleMenu, '(-');
AppleAboutProc := aboutProc;
END;
AddResMenu(appleMenu, 'DRVR');
SkelMenu(appleMenu, @DoAppleItem, @DoAppleClobber);
END;
{ -------------------------------------------------------------------- }
{ Window-handler interface routines }
{ -------------------------------------------------------------------- }
{ Install handler for a window. Remove any previous handler for it.}
{ Pass the following parameters:}
{ theWind Pointer to the window to be handled. Must be created by host.}
{ pMouse Proc to handle mouse clicks in window. The proc will be}
{ passed the point (in local coordinates), the time of the}
{ click, and the modifier flags word.}
{ pKey Proc to handle key clicks in window. The proc will be passed}
{ the character and the modifier flags word.}
{ pUpdate Proc for updating window. TransSkel brackets calls to update}
{ procs with calls to BeginUpdate and EndUpdate, so the visRgn}
{ is set up correctly. A flag is passed indicating whether the}
{ window was resized or not. BY CONVENTION, the entire portRect}
{ is invalidated when the window is resized. That way, the}
{ handler's update proc can redraw the entire content region}
{ without interference from BeginUpdate/EndUpdate. The flag}
{ is set to false after the update proc is called; the}
{ assumption is made that it will notice the resizing and}
{ respond appropriately.}
{ pActivate Proc to execute when window is activated or deactivated.}
{ A boolean is passed to it which is true if the window is}
{ coming active, false if it's going inactive.}
{ pClose Proc to execute when mouse clicked in close box. Useful}
{ mainly to temp window handlers that want to know when to}
{ self-destruct (with SkelRmveWind).}
{ pClobber Proc for disposal of handler's data structures}
{ pIdle Proc to execute when no events are pending.}
{ frontOnly True if pIdle should execute on no events only when}
{ theWind is frontmost, false if executes all the time. Note}
{ that if it always goes, everything else may be slowed down!}
{ If a particular procedure is not needed (e.g., key events are}
{ not processed by a handler), pass nil in place of the appropriate}
{ procedure address.}
{ All handler procedures may assume that the port is set correctly}
{ at the time they are called.}
PROCEDURE SkelWindow;
VAR
hHand : WhandlerHnd;
BEGIN
whClobOnRmve := false;
SkelRmveWind(theWind);
whClobOnRmve := true;
hHand := WHandlerHnd(NewHandle(Sizeof(WHandler)));
hHand^^.whNext := whList;
whList := hHand;
WITH hHand^^ DO
BEGIN
whWind := theWind;
whMouse := pMouse;
whKey := pKey;
whUpdate := pUpdate;
whActivate := pActivate;
whClose := pClose;
whClobber := pClobber;
whIdle := pIdle;
whFrontOnly := frontOnly;
whSized := false;
whGrow := GrowRect;
END;
SetPort(theWind);
END;
{ Remove a window handler. This calls the handler's disposal routine}
{ and then takes the handler out of the handler list and disposes}
{ of it.}
{ SkelRmveWind is also called by SkelRmveDlog.}
PROCEDURE SkelRmveWind;
VAR
h, h2 : WHandlerHnd;
returnflag : Boolean;
BEGIN
IF (whList <> NIL) THEN
BEGIN
returnflag := false;
IF whList^^.whWind = theWind THEN
BEGIN
h2 := whlist;
whList := whList^^.whNext;
END
ELSE
BEGIN
h := whList;
WHILE (h <> NIL) AND NOT returnflag DO
BEGIN
h2 := h^^.whNext;
IF (h2 = NIL) THEN
BEGIN
h := NIL;
returnflag := true;
END
ELSE IF h2^^.whWind = theWind THEN
BEGIN
h^^.whNext := h2^^.whNext;
h := NIL;
END;
IF h <> NIL THEN
h := h2;
END;
END;
IF NOT returnflag THEN
BEGIN
IF (whClobOnRmve) THEN
DoClobber(h2);
DisposHandle(Handle(h2));
END;
END;
END;
{ -------------------------------------------------------------------- }
{ Dialog-handler interface routines }
{ -------------------------------------------------------------------- }
{ Install a dialog handler. Remove any previous handler for it.}
{ SkelDialog calls SkelWindow as a subsidiary to install a window}
{ handler, then sets the event procedure on return.}
{ Pass the following parameters:}
{ theDialog Pointer to the dialog to be handled. Must be created}
{ by host.}
{ pEvent Event-handling proc for dialog events.}
{ pClose Proc to execute when mouse clicked in close box. Useful}
{ mainly to dialog handlers that want to know when to}
{ self-destruct (with SkelRmveDlog).}
{ pClobber Proc for disposal of handler's data structures}
{ If a particular procedure is not needed, pass nil in place of}
{ the appropriate procedure address.}
{ All handler procedures may assume that the port is set correctly}
{ at the time they are called.}
PROCEDURE SkelDialog;
VAR
wh : WHandlerHnd;
BEGIN
SkelWindow(theDialog, NIL, NIL, NIL, NIL, pClose, pClobber, NIL, false);
wh := GetWDHandler(theDialog);
wh^^.whEvent := pEvent;
END;
{ Remove a dialog and its handler}
PROCEDURE SkelRmveDlog;
BEGIN
SkelRmveWind(theDialog);
END;
{ -------------------------------------------------------------------- }
{ Miscellaneous interface routines }
{ -------------------------------------------------------------------- }
{ Override the default sizing limits for a window, or, if theWind}
{ is nil, reset the default limits used by SkelWindow.}
PROCEDURE SkelGrowBounds;
VAR
h : WHandlerHnd;
r : Rect;
BEGIN
IF theWind <> NIL THEN
SetRect(growRect, hLo, vLo, hHi, vHi)
ELSE
BEGIN
h := GetWHandler(theWind);
IF h <> NIL THEN
BEGIN
SetRect(r, hLo, vLo, hHi, vHi);
h^^.whGrow := r;
END;
END;
END;
{ Set the event mask.}
PROCEDURE SkelEventMask;
BEGIN
eventMask := mask;
END;
{ Return the event mask.}
PROCEDURE SkelGetEventMask;
BEGIN
mask := eventMask;
END;
{ Install a background task. If p is nil, the current task is}
{ disabled.}
PROCEDURE SkelBackground;
BEGIN
pBkgnd := p;
END;
{ Return the current background task. Return nil if none.}
PROCEDURE SkelGetBackground;
BEGIN
p := pBkgnd;
END;
{ Install an event-inspecting hook. If p is nil, the hook is}
{ disabled.}
PROCEDURE SkelEventHook;
BEGIN
pEvent := p;
END;
PROCEDURE SkelGetEventHook;
BEGIN
p := pEvent;
END;
{ Set the mask for event types that will be passed to dialogs.}
{ Bit 1 is always set, so that null events will be passed.}
PROCEDURE SkelDlogMask;
BEGIN
dlogEventMask := BitOr(mask, 1);
END;
{ Return the current dialog event mask.}
PROCEDURE SkelGetDlogMask;
BEGIN
mask := dlogEventMask;
END;
END.